package mastermind.logic;

import java.util.ArrayList;

import mastermind.dataholder.Row;

/**
 * Verwaltet die Routine, welche neue m&ouml;gliche L&ouml;sungen findet<br/>
 * Stellt grundlegende Funktionen zur &Uuml;berpr&uuml;fung bereit ob eine Row
 * eine g&uuml;ltige L&ouml;sung sein kann
 */
public class Solver
{
	private static ArrayList<ArrayList<Integer>>	_possible	= null;

	/**
	 * Alle Funktionen in der Klasse sind statisch<br>
	 * Es ist nicht n&ouml;tig ein Objekt davon zu erstellen
	 */
	private Solver()
	{}

	/**
	 * Berechnet neue L&ouml;sungen<br/>
	 * Die L&ouml;sungen werden in einem extra Thread berechnet. Dadurch ist es
	 * m&ouml;glich das Spielfeld weiterhin zu bedienen, ohne das die
	 * Oberfl&auml;che einfriert.<br/>
	 * Zudem kann ein Tipp bereits ausgew&auml;hlt und benutzt werden, auch wenn
	 * noch weitere Tipps berechnet werden.<br/>
	 * In dem Fall bricht die Berechnung der Tipps automatisch ab, sobald der
	 * Benutzer einen Tipp ausw&auml;hlt
	 */
	public static void run()
	{
		if (_possible == null || _possible.size() != Game.getCntHoles())
		{
			resetPossible();
		}

		// Eindeutig falsche Kombinationen entfernen
		removeEmptyFromList();
		selectFullFromList();
		removeWrongFromList();

		// Alle bisher laufenden Solverthreads beenden
		ThreadManager.killSolverThreads();

		// Neuen Solverthread erstellen und starten
		SolverThread solverThread = new SolverThread();
		ThreadManager.addSolverThread(solverThread);
		solverThread.start();
	}

	/**
	 * Sucht nach Reihen, in denen nur falsche Bewertungspins stecken und
	 * entfernt die Farben von der benutzen Position aus der Liste
	 */
	private static void removeWrongFromList()
	{
		for (Row row : Game.getHistory())
		{
			// Es sind nur Falsch-Pins gesetzt
			if (row.getRightPlaces() == 0 && row.getWrongPlaces() != 0)
			{
				// Alle vorhanden Farben entfernen
				for (int hole = 0; hole < Game.getCntHoles(); hole++)
				{
					_possible.get(hole).remove(new Integer(row.getColor(hole)));
				}
			}
		}
	}

	/**
	 * Sucht nach einer Reihe in der die maximal m&ouml;gliche Anzahl
	 * Bewertungspins stecken und entfernt alle anderen Farben aus der Liste
	 */
	private static void selectFullFromList()
	{
		for (Row row : Game.getHistory())
		{
			// Es sind die maximale Anzahl Pins gesetzt
			if (row.getRightPlaces() + row.getWrongPlaces() == Game.getCntHoles())
			{
				// Alle moeglichen Farben durchgehen
				for (int col = 0; col < Game.getCntColors(); col++)
				{
					// Ist diese Farbe in der Reihe vorhanden?
					boolean found = false;
					for (int hole = 0; hole < Game.getCntHoles(); hole++)
					{
						if (row.getColor(hole) == col)
						{
							found = true;
							break;
						}
					}
					// Wenn nicht vorhanden, darf sie in der Loesung nicht
					// vorkommen
					if (!found)
					{
						for (ArrayList<Integer> list : _possible)
						{
							list.remove(new Integer(col));
						}
					}
				}
			}
		}
	}

	/**
	 * Sucht nach Reihen in denen keine Bewertungspins stecken und entfernt die
	 * benutzen Farben von der Liste
	 */
	private static void removeEmptyFromList()
	{
		for (Row row : Game.getHistory())
		{
			// Es sind die maximale Anzahl Pins gesetzt
			if (row.getRightPlaces() + row.getWrongPlaces() == 0)
			{
				// Alle vorhanden Farben entfernen
				for (int hole = 0; hole < Game.getCntHoles(); hole++)
				{
					for (ArrayList<Integer> list : _possible)
					{
						list.remove(new Integer(row.getColor(hole)));
					}
				}
			}
		}
	}

	/**
	 * Gibt die m&ouml;glichen Farben f&uuml;r jede Position zur&uuml;ck
	 * 
	 * @return Die m&ouml;glichen Farben f&uuml;r jede Position
	 */
	public static ArrayList<ArrayList<Integer>> getPossible()
	{
		return _possible;
	}

	/**
	 * Neues Spiel, neues Gl&uuml;ck ;-)<br/>
	 * Alles zur&uuml;cksetzen. Es ist jetzt wieder alles m&ouml;glich
	 */
	public static void resetPossible()
	{
		_possible = new ArrayList<ArrayList<Integer>>();
		for (int i = 0; i < Game.getCntHoles(); i++)
		{
			ArrayList<Integer> list = new ArrayList<Integer>();
			for (int j = 0; j < Game.getCntColors(); j++)
			{
				list.add(j);
			}
			_possible.add(list);
		}
	}
}
